#include "GCoordFrame2.h"
#include "GTransform2.h"

namespace GMath
{
	const GCoordFrame2 GCoordFrame2::Identitiy = GCoordFrame2(GVector2::One, 0.0f, GVector2::Zero);

	GCoordFrame2::GCoordFrame2()
	{
		Scale = GVector2::One;
		Rotation = 0.0f;
		Position = GVector2::Zero;

		Transformation = GMatrix3x3::Identity;

		Right = GVector2::UnitX;
		Up = GVector2::UnitY;

		Flags.LowerAll();
	}
	
	GCoordFrame2::GCoordFrame2(const GCoordFrame2& Frame)
	{
		*this = Frame;
	}
	
	GCoordFrame2::GCoordFrame2(const GVector2& Scale, float Rotation, const GVector2& Position)
	{
		SetScale(Scale);
		SetRotation(Rotation);
		SetPosition(Position);
	}

	GCoordFrame2::~GCoordFrame2()
	{
	}

	GFrame2DirtyFlags GCoordFrame2::GetFlags() const
	{
		return Flags;
	}

	void GCoordFrame2::SetScale(const GVector2& NewScale)
	{
		Scale = NewScale;

		Flags.RaiseBits(G_F2DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GVector2& GCoordFrame2::GetScale() const
	{
		return Scale;
	}

	void GCoordFrame2::SetPosition(const GVector2& NewPosition)
	{
		Position = NewPosition;

		Flags.RaiseBits(G_F2DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GVector2& GCoordFrame2::GetPosition() const
	{
		return Position;
	}

	void GCoordFrame2::SetRotation(float NewRotation)
	{
		Rotation = NewRotation;

		Flags.RaiseBits(G_F2DF_DIRTY_AXIS);
		Flags.RaiseBits(G_F2DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	float GCoordFrame2::GetRotation() const
	{
		return Rotation;
	}

	void GCoordFrame2::SetTransformation(const GMatrix3x3& Matrix)
	{
		GMatrix3x3::Decompose(Scale, Rotation, Position, Matrix);
		Flags.RaiseBits(G_F2DF_DIRTY_AXIS | G_F2DF_DIRTY_TRANSFORM);

		OnTransformChange();
	}

	const GMatrix3x3& GCoordFrame2::GetTransformation() const
	{
		if (Flags.Contains(G_F2DF_DIRTY_TRANSFORM))
		{
			GTransform2::CreateLocal(Transformation, GetScale(), GetRotation(), GetPosition());
			Flags.LowerBits(G_F2DF_DIRTY_TRANSFORM);
		}

		return Transformation;
	}

	const GVector2& GCoordFrame2::GetRight() const
	{
		if (Flags.Contains(G_F2DF_DIRTY_RIGHT))
		{
			GMatrix3x3 RotMatrix;
			GTransform2::CreateRotation(RotMatrix, GetRotation());
			
			GMatrix3x3::Multiply(Right, GVector2::UnitX, RotMatrix);
			Flags.LowerBits(G_F2DF_DIRTY_RIGHT);
		}

		return Right;
	}

	const GVector2& GCoordFrame2::GetUp() const
	{
		if (Flags.Contains(G_F2DF_DIRTY_UP))
		{
			GMatrix3x3 RotMatrix;
			GTransform2::CreateRotation(RotMatrix, GetRotation());
			
			GMatrix3x3::Multiply(Up, GVector2::UnitY, RotMatrix);
			Flags.LowerBits(G_F2DF_DIRTY_UP);
		}

		return Up;
	}

	const GCoordFrame2& GCoordFrame2::operator = (const GCoordFrame2& Frame)
	{
		Scale = Frame.Scale;
		Rotation = Frame.Rotation;
		Position = Frame.Position;
		Transformation = Frame.Transformation;
		Right = Frame.Right;
		Up = Frame.Up;
		Flags = Frame.Flags;

		return *this;
	}

	void GCoordFrame2::OnTransformChange()
	{
	}
}